Amazon EC2(Linux)のswap領域ベストプラクティス
ども、大瀧です。
Linuxのメモリ管理で欠かせないのがswapですよね。EC2のディスク管理には独特な仕様があるのでその辺りを踏まえつつ、EC2(Linux)でどのようにswap領域を用意するのが良いのかまとめてみたいと思います。
理屈をこねながらの解説になるので、先に本エントリーの結論を。
- 公式AMIにはswap領域が含まれない
- m1.small、c1.mediumには900MBのスワップ領域がおまけでついてくる(Amazon Linux AMIであれば、Cloud-initによって自動マウントされる)
- swap領域には、インスタンスストア(別名Ephemeral Disk)を使うべし
では、それぞれ見ていきます。
公式Linux AMIの初期構成にはswapパーティションが無い
Amazonから提供される公式のLinux AMIのブートディスクには、swapパーティションが含まれていません。以下にAmazon Linuxでのfdiskコマンドの結果を示します。
[ec2-user@ip-XX-XX-XX-XX ~] $ sudo fdisk -l /dev/sda1 ディスク /dev/sda1: 8589 MB, 8589934592 バイト ヘッド 255, セクタ 63, シリンダ 1044 Units = シリンダ数 of 16065 * 512 = 8225280 バイト セクタサイズ (論理 / 物理): 512 バイト / 512 バイト I/O size (minimum/optimal): 512 bytes / 512 bytes ディスク識別子: 0x00000000 [ec2-user@ip-XX-XX-XX-XX ~] $
一般の物理マシンではブートディスクの末尾付近にswapパーティションを切ることが多いですが、EC2ではEBSのディスク拡張でルートパーティションが拡張できるよう、ブートディスクにはパーティションテーブルが意図して作成されないことが推測できます。また、EC2はインスタンスタイプを変更することでメモリサイズが変化するため、swapパーティションのサイズを事前に決めることが難しいというのも背景としてありそうです。
というわけで、そのままでは万が一メモリフルになるとOOM Killerさんが早々に大ナタを振るうことになってしまいます。何らかの方法でswap領域を確保しましょう。
EC2インスタンスストアスワップボリューム
swap領域を確保する一番手っ取り早い方法として、EC2のインスタンスストアスワップボリュームがあります。これは、EC2のインスタンスタイプがm1.smallとc1.mediumのときのみ/dev/xvda3ないし/dev/xvde3という900MBのmkswap済みディスクがEC2のブート時に自動で提供されます(デバイス名はAMIによりまちまちです)。他のインタンスタイプではm1/c1ファミリーであっても提供されず、またManagement ConsoleやAWS APIでは本ボリュームを確認できないことに注意しましょう。
コメントでmacotomiiさんからご指摘いただいた通り、AWS Marketplaceで提供されるCentOS AMIでは現状インスタンスストアスワップボリュームが検出されないようです。
Amazon Linuxであれば、前回のエントリーでも触れたcloud-initというツールによってこのswap領域をマウントするエントリーが/etc/fstabに追記され、自動でswaponされます。Amazon Linuxでのfreeコマンドの結果を以下に示します。
m1.smallの場合
[ec2-user@ip-XX-XX-XX-XX ~]$ free total used free shared buffers cached Mem: 1696516 94700 1601816 0 7000 41032 -/+ buffers/cache: 46668 1649848 Swap: 917500 0 917500
c1.mediumの場合
[ec2-user@ip-XX-XX-XX-XX ~]$ free total used free shared buffers cached Mem: 1737192 116856 1620336 0 7084 60808 -/+ buffers/cache: 48964 1688228 Swap: 917500 0 917500
m1.mediumの場合(スワップボリュームの無いタイプ)
[ec2-user@ip-XX-XX-XX-XX ~]$ free total used free shared buffers cached Mem: 3844408 105340 3739068 0 7000 43120 -/+ buffers/cache: 55220 3789188 Swap: 0 0 0
c1.xlargeの場合(スワップボリュームの無いタイプ)
[ec2-user@ip-XX-XX-XX-XX ~]$ free total used free shared buffers cached Mem: 7118660 149228 6969432 0 7108 60844 -/+ buffers/cache: 81276 7037384 Swap: 0 0 0
自動で使え、かつ無料なので便利ではあるのですが、スケールアップ/ダウンなどでインスタンスタイプを変更すると使えなくなってしまうので、おまけで使えればラッキー☆くらいに見ておくのが良いでしょう。「本番環境の運用時に本ボリュームのないタイプに変更したら急にOOM Killerが発動するようになってしまった」など、ハマる可能性大です。最近は、m3やc3から始まる新しい世代のインスタンスファミリーが出てきており、コストパフォーマンスや性能向上を狙ってインスタンスファミリーを移行(m1→m3、c1→c3)しようとして同様にハマることもありそうです。
swapファイルのススメ
スワップのためにボリュームやパーティーションを追加するのは、EBSがボリュームサイズで課金されることからコスト面で敷居が高いです。そのため、既存ボリュームにswapファイルを追加のがお奨めです。
作成するべきスワップサイズは先人の知恵を拝借しつつ、可能であればインスタンスタイプ毎にスワップファイルサイズを調整できるよう、EC2の起動時にswapファイルを作成、マウントするといいですね。/etc/rc.localやcloud-initの力を借りると良さそうです。以下に例を示します。
/etc/rc.localに追記する例
2018/01/25更新 : 記事のコメントでエラーになるという指摘があり、一部修正しました。
SWAPFILENAME=/swap.img MEMSIZE=`cat /proc/meminfo | grep MemTotal | awk '{print $2}'` if [ $MEMSIZE -lt 2097152 ]; then SIZE=$((MEMSIZE * 2))k elif [ $MEMSIZE -lt 8388608 ]; then SIZE=${MEMSIZE}k elif [ $MEMSIZE -lt 67108864 ]; then SIZE=$((MEMSIZE / 2))k else SIZE=4194304k fi fallocate -l $SIZE $SWAPFILENAME && mkswap $SWAPFILENAME && swapon $SWAPFILENAME
ちょっと工夫したところは、swap用のイメージファイルの作成にddコマンドではなくfallocateコマンドを使っている点です。従来のswapファイルであれば一度作るだけなので実行に時間のかかるddコマンドでも問題なかったのですが、今回はインスタンス起動時に毎回実行するので、より時間のかからない方法にしました。ddコマンドと異なりI/Oも最小限なので、I/O単位で課金が発生するEBSでもお財布に優しいですよね。
インスタンスストアの活用
swapファイルを作成するボリュームは、特に種類を問いません。しかし、EBSだとI/O単位で課金が発生するためスワップアウト/インが頻発する状況だとディスクI/Oの課金がかさんでしまう可能性があります。
そこで、swapファイルはインスタンスストア(通称 : Ephemeral Disk)に作成することをオススメします。インスタンスストアは無料で使えるローカルボリュームで、インスタンスタイプ毎に本数とサイズが決まっています。以下の注意点を見つつ、うまく使いましょう。
- AMIで事前に設定されていない場合、インスタンス起動時に追加しなければならない
- インスタンスをStopするタイミングで内容が全て消えるので、インスタンス起動時に毎回swapファイルを作成しなければならない
上記スクリプトのfallocateコマンドはext4ファイルシステムに依存する機能を利用しており、インスタンスストアの既定のファイルシステムがext3のためインスタンスストア上にswapファイルを作成しようとすると、エラーになります。fallocateコマンドを使うためには、起動処理でのマウント(=cloud-initサービスのstart処理)の前にインスタンスストアのファイルシステムをext4に変更する必要があります。これは/etc/rc.localでは対応できないので、独自サービスを定義したパッケージを作成してみました。こちらの記事をどうぞ!
まとめ
というわけで、冒頭の要点を改めて示します。
- 公式AMIにはswap領域が含まれない
- m1.small、c1.mediumには900MBのスワップ領域がおまけでついてくる(Amazon Linux AMIであれば、Cloud-initによって自動マウントされる)
- swap領域には、インスタンスストア(別名Ephemeral Disk)を使うべし
最近はメモリに余裕を持ったシステム構成が多いと思いますが、メモリ管理の予防線としてswapの構成もしっかり検討しましょう!